﻿using Bomber.TF.Common.GDI;
using Bomber.TF.GameCenter.BombCenter;
using Bomber.TF.GameCenter.ToolCenter;
using Microsoft.VisualBasic;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bomber.TF.GameCenter.BomberCenter
{
    public unsafe abstract class BomberBase : GameBase
    {
        protected ConcurrentQueue<int> _curPlayIndexs;
        protected BombBase _bombBase;
        public BomberBase(SpeciesType speciesType, Size size)
            : base(speciesType, size)
        {
            _curPlayIndexs = new ConcurrentQueue<int>();
        }
        public int DefaultRow { get; set; }
        public int DefaultColumn { get; set; }
        public int BombCount { get; set; } = 1;
        public int BombRange { get; set; } = 1;
        public int Life { get; set; } 
        public Action<BomberBase>? DeathCallback;
        protected int _playIndex = 0;
        public override unsafe void Business(GameListBase* ptr)
        {
            if (_isAttacked && _lastIndex < 12)
                --this.Life;
            if(_lastIndex==13 && _curPlayIndexs.Count == 0 && this.Life <= 0)
                DeathCallback?.Invoke(this);// 死亡 生命值=0

            if (_lastIndex == 14 && _curPlayIndexs.Count == 0)
            {
                GameListBase* p = ptr + base.Row * base.MaxColumn + base.Column;
                p->Games.Remove(this);
                if (this.Life > 0)
                {
                    _lastIndex = -1;
                    this.Row = this.DefaultRow;
                    this.Column = this.DefaultColumn;
                    this.UpdateLocation();
                    (ptr + this.DefaultRow * base.MaxColumn + this.DefaultColumn)->Games.Add(this);
                }
                
                _isAttacked = false;
            }
            else
                _playIndex = GetIndex();
        }
        protected bool _isAttacked = false;
        public virtual void Attacked()
        {
            if (_isAttacked) return;

            _isAttacked = true;
            _curPlayIndexs.Clear();
            for (int i = 0; i < COUNT; i++)
            {
                _curPlayIndexs.Enqueue(12);
            }
            for (int i = 0; i < COUNT; i++)
            {
                _curPlayIndexs.Enqueue(13);
            }
            if (this.Life >1)
            {
                for (int i = 0; i < COUNT * 2; i++)
                {
                    _curPlayIndexs.Enqueue(14);
                }
            }
        }
        const int COUNT = 6;
        public virtual void Up(GameListBase* set)
        {
            if (_isAttacked) return;

            int nextRow = this.Row - 1;
            int y = base.Location.Y - base.CellHeight / 2;
            int upperY = StartY + nextRow * CellHeight;
            GameListBase* ptr = set + nextRow * MaxColumn + base.Column;
            if (y < upperY + CellHeight
                && ptr->Games.Count != 0
                && ptr->Games.Any(t => t.IsBlock || t.IsBomb))
                goto Here;

            int row = (int)Math.Ceiling((y - base.StartY) / (float)base.CellHeight);
            Update(set, ptr, row, base.Column, Location.X, y);

        Here:
            AddIndex(4, 5);
        }
        public virtual void Down(GameListBase* set)
        {
            if (_isAttacked) return;

            int nextRow = this.Row + 1;
            int y = base.Location.Y + base.CellHeight / 2;
            int lowerY = StartY + nextRow * CellHeight;
            GameListBase* ptr = set + nextRow * MaxColumn + base.Column;
            if (y + Size.Height > lowerY
                && ptr->Games.Count != 0
                && ptr->Games.Any(t => t.IsBlock || t.IsBomb))
                goto Here;

            int row =(int)Math.Ceiling((y - base.StartY) / (float)base.CellHeight);
            Update(set, ptr, row, base.Column, Location.X, y);
        Here:
            AddIndex(10, 11);
        }
        public virtual void Left(GameListBase* set)
        {
            if (_isAttacked) return;

            int nextCol = base.Column - 1;
            int x = base.Location.X - base.CellWidth / 2;
            int leftX = StartX + nextCol * CellWidth;
            GameListBase* ptr = set + base.Row * MaxColumn + nextCol;
            if (x - leftX <= base.CellWidth / 2
               && ptr->Games.Count != 0
               && ptr->Games.Any(t => t.IsBlock || t.IsBomb))
                goto Here;

            int col = (int)Math.Ceiling((x - StartX) / (float)base.CellWidth);
            Update(set, ptr, base.Row, col, x, Location.Y);
        Here:
            AddIndex(1, 2);
        }
        public virtual void Right(GameListBase* set)
        {
            if (_isAttacked) return;

            int nextCol = base.Column + 1;
            int x = base.Location.X + base.CellWidth / 2;
            int rightX = StartX + nextCol * CellWidth;
            GameListBase* ptr = set + base.Row * MaxColumn + nextCol;
            if (x + Size.Width > rightX
               && ptr->Games.Count != 0
               && ptr->Games.Any(t => t.IsBlock || t.IsBomb))
                goto Here;

            int col = (int)Math.Ceiling((x - StartX) / (float)base.CellWidth);
            Update(set, ptr, base.Row, col, x, Location.Y);
        Here:
            AddIndex(7, 8);
        }
        public virtual void Space(GameListBase* set)
        {
            if (_isAttacked) return;
            if (_bombBase == null) return;
            if (this.BombCount <= 0) return;
            --this.BombCount;
            CreateBomb(set);
        }
        private void CreateBomb(GameListBase* set)
        {
            GameListBase* ptr = set + this.Row * this.MaxColumn + this.Column;
            var bomb = (BombBase)_bombBase.Clone();
            SetParameter(bomb);
            ptr->Games.Add(bomb);
        }
        private void SetParameter(GameBase gameBase)
        {
            gameBase.MaxRow = this.MaxRow;
            gameBase.MaxColumn = this.MaxColumn;
            gameBase.StartX = this.StartX;
            gameBase.StartY = this.StartY;
            gameBase.CellWidth = this.CellWidth;
            gameBase.CellHeight = this.CellHeight;
            gameBase.ZoomX = this.ZoomX;
            gameBase.ZoomY = this.ZoomY;
            gameBase.Row = this.Row;
            gameBase.Column = this.Column;
            gameBase.UpdateLocation();
        }
        private void AddIndex(int a, int b)
        {
            _curPlayIndexs.Clear();
         
            for (int i = 0; i < 3; i++)
            {
                _curPlayIndexs.Enqueue(a);
                _curPlayIndexs.Enqueue(b);
            }
        }
       
        private void Update(GameListBase* set, GameListBase* ptr, int row, int col, int x, int y)
        {
            if (base.Row != row || base.Column != col)
            {
                GameListBase* temp = set + base.Row * MaxColumn + base.Column;
                ptr->Games.Add(this);
                temp->Games.Remove(this);
                base.Column = col;
                base.Row = row;
                GatherTool(ptr);
            }
            Location = new Point(x, y);
        }
        private void GatherTool(GameListBase* ptr)
        {
            GameBase? first = ptr->Games.FirstOrDefault(t => t.IsTool);
            if (first == null) return;
            ptr->Games.Remove(first);
            ToolBase? toolBase = first as ToolBase;
            toolBase?.Upgradation(this);
        }

        private int _lastIndex = -1;
        private DateTime _deathTime = DateTime.MinValue;
        protected int GetIndex()
        {
            if (_curPlayIndexs.Count == 0)
            {
                if (_lastIndex == -1)
                    _lastIndex = 9;
                else
                {
                    if (_lastIndex == 0 || _lastIndex == 3 || _lastIndex == 6 || _lastIndex == 9)
                    {

                    }
                    else if (_lastIndex == 1 || _lastIndex == 2)
                        _lastIndex = 0;
                    else if (_lastIndex == 4 || _lastIndex == 5)
                        _lastIndex = 3;
                    else if (_lastIndex == 7 || _lastIndex == 8)
                        _lastIndex = 6;
                    else if (_lastIndex == 10 || _lastIndex == 11)
                        _lastIndex = 9;
                }
            }
            else
            {
                bool status = false;
                if (_lastIndex == 13 && _curPlayIndexs.TryPeek(out var inde) && inde == 14)
                {
                    if ((DateTime.Now - _deathTime).TotalSeconds >= 5)
                        status = true;
                }
                else
                {
                    status = true;
                }
                if (status)
                {
                    if (_curPlayIndexs.TryDequeue(out int index))
                    {
                        if (_lastIndex == 12 && index == 13)
                            _deathTime = DateTime.Now;
                        _lastIndex = index;
                    }
                }
            }
            return _lastIndex;

        }
        protected void SetBomb(BombBase bombBase)
        {
            if (_bombBase != null)
                _bombBase.BlastCallback -= Blast;
            _bombBase = bombBase;
            _bombBase.BlastCallback += Blast;
        }
        /// <summary>
        /// 炸弹爆炸回调
        /// </summary>
        /// <param name="bombBase"></param>
        protected virtual void Blast(BombBase bombBase)
        {
            ++BombCount;
        }
    }
}
